/*
 * Copyright (C) 2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "aki/jsbind.h"


aki::Promise CreatePromiseRejectAndCatch()
{
    aki::Promise promise;
    std::thread t([promise] () {
        aki::TaskRunner::PostTask("main", [promise] () {
            const int notFound = 404;
            promise.Reject(notFound);
        });
    });
    t.detach();
    
    std::function<int(int)> errorFunc = [](int errorCode)->int {
        AKI_LOG(INFO) << "reject error, code: "<<errorCode;
        // catch处理后返回会更新Promise状态,将继续触发后续链式调用的then
        return 200;
    };
    
    return promise.Catch(errorFunc);
}

aki::Promise CreatePromiseLongChain()
{
    aki::Promise promise;
    promise.Resolve(1);
    
    std::function<int(int)> func = [](int num)->int {
        AKI_LOG(INFO)<< "Got a num from previous promise: " << num;
        return num+1;
    };
    
    return promise.Then<int, int>([](int num)->int {
        const int testNumber = 9;
        AKI_LOG(INFO) << "Template specify use then got a num: "<< num;
        return num+testNumber;
    }).Then(func).Then(func).Then(func).Then(func).Then(func).Then(func);
}

void CreatePromiseThenCatchResolve()
{
    aki::Promise promise;
    std::thread t([promise] () {
        // Task Runner 需要在dts中导出并在js中init
        aki::TaskRunner::PostTask("main", [promise] () {
            // 不能在C线程中执行
            promise.Resolve("task finished!");
        });
    });
    t.detach();
    
    promise.Then<std::string, std::string, void, std::string>([](std::string info)->std::string {
        AKI_LOG(INFO)<<"task success, got info: "<<info;
        return "then function finished";
        }, [](std::string error) {
        AKI_LOG(INFO)<<"task failed, erorr:"<<error;
    });
}

void ProcessJsPromise(aki::Promise promise)
{
    promise.Then<void, std::string>([](std::string info) {
        AKI_LOG(INFO) <<"got info from js promise: "<<info;
    }).Catch<void, std::string>([](std::string error) {
        AKI_LOG(INFO) <<"reject from js promise: "<<error;
    });
}

void ProcessJsPromiseExceptionThrowCatch(aki::Promise promise)
{
    promise.Catch<int, int>([](int errorCode)->int {
        const int ok = 100;
        AKI_LOG(INFO) << "catch reject error from js, errorcode: "<<errorCode;
        return ok;
    }).Then<void, int>([](int num) {
        AKI_LOG(INFO) << "got number after catched reject error : " << num;
        
        // 抛出一个js 异常
        napi_throw_error(aki::Binding::GetScopedEnv(), "500", "throw exception and catch again");
    }).Catch<void, aki::Value>([](aki::Value error) {
        // 再次捕获, js异常需要使用aki::Value来接收, 映射为JS中的Error对象.
        if (error.IsError()) {
            AKI_LOG(INFO) << "catch error: " << error["message"].As<std::string>()
                      << ", error Code: " << error["code"].As<std::string>();
        }
    });
}

JSBIND_GLOBAL()
{
    JSBIND_FUNCTION(CreatePromiseRejectAndCatch);
    JSBIND_FUNCTION(CreatePromiseLongChain);
    JSBIND_FUNCTION(CreatePromiseThenCatchResolve);
    JSBIND_FUNCTION(ProcessJsPromise);
    JSBIND_FUNCTION(ProcessJsPromiseExceptionThrowCatch);
}

JSBIND_ADDON(entry)